package main

import (
	"context"
	"fmt"
	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/chromedp"
	"github.com/go-json-experiment/json"
	"log"
	"strings"
	"sync"
	"time"
	"wxReadShare/logger"
	"wxReadShare/pie"
)

// 获取章节信息
func GetChapter(logg logger.Logger, cache *pie.FileCache, bookId string) {
	// 设置书籍阅读器URL
	//url := "https://weread.qq.com/web/reader/e223200071c3a8e5e229d2f"

	url := fmt.Sprintf("https://weread.qq.com/web/reader/%s", bookId)

	// 1. 创建浏览器配置
	opts := append(chromedp.DefaultExecAllocatorOptions[:],
		chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"),
		chromedp.WindowSize(1920, 1080),
		chromedp.Flag("headless", true),
	)

	// 2. 创建浏览器上下文
	allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
	defer cancel()

	ctx, cancel := chromedp.NewContext(allocCtx)
	defer cancel()

	ctx, cancel = context.WithTimeout(ctx, 20*time.Second)
	defer cancel()

	// 3. 创建控制台消息监控器
	consoleMonitor := NewConsoleMonitor()

	// 4. 执行目录提取任务
	var tocJSON string
	var bookTitle string

	logg.Info("开始监控控制台并获取书籍目录...")
	startTime := time.Now()

	// 创建任务列表
	tasks := chromedp.Tasks{
		// 注册控制台消息监听器
		chromedp.ActionFunc(func(ctx context.Context) error {
			chromedp.ListenTarget(ctx, func(ev interface{}) {
				if consoleMessage, ok := ev.(*runtime.EventConsoleAPICalled); ok {
					msg := formatConsoleMessage(consoleMessage)
					consoleMonitor.ProcessMessage(msg)
					logg.Infof("控制台消息: %s", msg)
				}
			})
			return nil
		}),

		// 启用网络域
		//network.Enable(),
		// 屏蔽不必要资源
		//chromedp.ActionFunc(func(ctx context.Context) error {
		//	return network.SetBlockedURLs([]string{
		//		"*.jpg", "*.jpeg", "*.png", "*.gif", "*.webp",
		//		"*.woff", "*.woff2", "*.ttf", "*.svg",
		//		"*.css",
		//		"*.mp4", "*.mpeg", "*.avi", "*.mov",
		//	}).Do(ctx)
		//}),

		// 导航到阅读器页面
		chromedp.Navigate(url),

		// 等待JSBridge就绪
		consoleMonitor.WaitForMessage("JSBridge is ready", 18*time.Second),

		// 等待页面标题加载
		chromedp.WaitVisible(`.readerTopBar_title`, chromedp.ByQuery),

		// 获取书籍标题
		chromedp.Text(`.readerTopBar_title`, &bookTitle, chromedp.ByQuery),

		// 点击目录按钮 - 修正语法错误
		chromedp.Click(`.readerControls_item.catalog`, chromedp.ByQuery, chromedp.NodeVisible),

		// 等待目录列表加载
		chromedp.WaitVisible(`.readerCatalog_list`, chromedp.ByQuery),

		// 确保目录项完全加载
		// chromedp.Sleep(2 * time.Second),

		// 直接在浏览器环境中解析目录
		chromedp.Evaluate(`
			function parseCatalog() {
				const toc = [];
				const items = document.querySelectorAll('.readerCatalog_list > .readerCatalog_list_item');
				
				if (!items || items.length === 0) {
					console.error('未找到目录项');
					return JSON.stringify([]);
				}
				
				for (const item of items) {
					try {
						// 确保元素在DOM中
						if (!item.isConnected) continue;
						
						const inner = item.querySelector('.readerCatalog_list_item_inner');
						if (!inner) {
							console.warn('未找到内部容器:', item);
							continue;
						}
						
						const titleElem = inner.querySelector('.readerCatalog_list_item_title_text');
						const title = titleElem ? titleElem.textContent.trim() : '未知标题';
						
						// 提取层级信息
						let level = '0';
						for (const className of inner.classList) {
							if (className.startsWith('readerCatalog_list_item_level_')) {
								level = className.replace('readerCatalog_list_item_level_', '');
								break;
							}
						}
						
						toc.push({
							title: title,
							level: level,
							selected: item.classList.contains('readerCatalog_list_item_selected'),
							disabled: item.classList.contains('readerCatalog_list_item_disabled')
						});
					} catch (e) {
						console.error('解析目录项失败:', e, item);
					}
				}
				return JSON.stringify(toc);
			}
			parseCatalog();
		`, &tocJSON),

		// 调试：保存页面截图
		//chromedp.ActionFunc(func(ctx context.Context) error {
		//	var buf []byte
		//	if err := chromedp.CaptureScreenshot(&buf).Do(ctx); err != nil {
		//		log.Printf("截图失败: %v", err)
		//		return nil
		//	}
		//	if err := os.WriteFile("catalog_screenshot.png", buf, 0644); err != nil {
		//		log.Printf("保存截图失败: %v", err)
		//	} else {
		//		log.Println("已保存目录截图: catalog_screenshot.png")
		//	}
		//	return nil
		//}),
	}

	// 执行任务
	err := chromedp.Run(ctx, tasks)

	duration := time.Since(startTime)
	if err != nil {
		logg.Infof("获取目录失败 (耗时: %v): %v", duration.Round(time.Millisecond), err)
	}

	logg.Infof("目录解析完成 (耗时: %v)", duration.Round(time.Millisecond))
	logg.Infof("获取的目录JSON长度: %d 字节", len(tocJSON))

	// 5. 解析并保存目录
	if tocJSON != "" {
		saveTOC(logg, cache, tocJSON, bookId)
		// displayTOC(tocJSON)
	} else {
		log.Println("未获取到目录数据")
	}

	// 6. 打印关键控制台事件
	// consoleMonitor.PrintKeyEvents()
}

// ConsoleMonitor 控制台消息监控器
type ConsoleMonitor struct {
	messages      []string
	keyEvents     []string
	ready         chan struct{}
	readyMsg      string
	mu            sync.Mutex
	startTime     time.Time
	jsBridgeReady bool
}

// NewConsoleMonitor 创建新的控制台监控器
func NewConsoleMonitor() *ConsoleMonitor {
	return &ConsoleMonitor{
		ready:     make(chan struct{}),
		startTime: time.Now(),
	}
}

// ProcessMessage 处理控制台消息
func (m *ConsoleMonitor) ProcessMessage(msg string) {
	m.mu.Lock()
	defer m.mu.Unlock()

	// 记录所有消息
	m.messages = append(m.messages, msg)

	// 检查关键事件
	if strings.Contains(msg, "JSBridge is running") {
		m.keyEvents = append(m.keyEvents, fmt.Sprintf("[%.2fs] %s", time.Since(m.startTime).Seconds(), msg))
	}

	if strings.Contains(msg, "JSBridge is initialized") {
		m.keyEvents = append(m.keyEvents, fmt.Sprintf("[%.2fs] %s", time.Since(m.startTime).Seconds(), msg))
	}

	// 检查就绪消息
	if strings.Contains(msg, "JSBridge is ready") {
		m.keyEvents = append(m.keyEvents, fmt.Sprintf("[%.2fs] %s", time.Since(m.startTime).Seconds(), msg))
		m.jsBridgeReady = true
		if m.readyMsg != "" {
			select {
			case <-m.ready:
				// 通道已关闭，不需要再次关闭
			default:
				close(m.ready)
			}
		}
	}
}

// WaitForMessage 等待特定消息
func (m *ConsoleMonitor) WaitForMessage(msg string, timeout time.Duration) chromedp.Action {
	return chromedp.ActionFunc(func(ctx context.Context) error {
		m.mu.Lock()
		m.readyMsg = msg

		// 如果消息已经出现，直接返回
		if m.jsBridgeReady {
			// log.Printf("JSBridge 已经就绪，继续执行")
			m.mu.Unlock()
			return nil
		}
		m.mu.Unlock()

		// log.Printf("等待消息: %s (超时: %v)", msg, timeout)

		// 设置超时
		ctx, cancel := context.WithTimeout(ctx, timeout)
		defer cancel()

		select {
		case <-ctx.Done():
			// log.Printf("等待消息超时: %s", ctx.Err())
			return ctx.Err()
		case <-m.ready:
			// log.Printf("收到消息: %s，继续执行", msg)
			return nil
		}
	})
}

// PrintKeyEvents 打印关键事件
func (m *ConsoleMonitor) PrintKeyEvents() {
	if len(m.keyEvents) == 0 {
		log.Println("未捕获到关键控制台事件")
		return
	}

	fmt.Println("\n=== 关键控制台事件 ===")
	for _, event := range m.keyEvents {
		fmt.Println(event)
	}
	fmt.Printf("共捕获 %d 个关键事件\n", len(m.keyEvents))
}

// 格式化控制台消息
func formatConsoleMessage(ev *runtime.EventConsoleAPICalled) string {
	var args []string
	for _, arg := range ev.Args {
		args = append(args, string(arg.Value))
	}
	return strings.Join(args, " ")
}

// 保存目录到文件
func saveTOC(logg logger.Logger, cache *pie.FileCache, tocJSON string, bookId string) {
	if tocJSON == "" {
		log.Println("无目录数据可保存")
		return
	}

	safeTitle := sanitizeFilename(bookId)
	filename := fmt.Sprintf("%s_toc.json", safeTitle)

	// 直接保存JSON字符串
	//if err := os.WriteFile(filename, []byte(tocJSON), 0644); err != nil {
	//	log.Printf("文件保存失败: %v", err)
	//} else {
	//	log.Printf("目录已保存到 %s", filename)
	//}

	// 保存到缓存
	if err := cache.Set(filename, []byte(tocJSON)); err != nil {
		logg.Infof("Failed to set cache: %v\n", err)
	}
}

// 显示目录
func displayTOC(tocJSON string) {
	if tocJSON == "" {
		fmt.Println("无目录数据显示")
		return
	}

	log.Printf("原始目录JSON: %s", tocJSON)

	// 解析JSON
	var toc []map[string]interface{}
	if err := json.Unmarshal([]byte(tocJSON), &toc); err != nil {
		log.Printf("解析目录JSON失败: %v", err)
		// 尝试修复常见的JSON问题
		if strings.HasPrefix(tocJSON, `"`) && strings.HasSuffix(tocJSON, `"`) {
			log.Println("尝试去除多余的引号")
			tocJSON = strings.Trim(tocJSON, `"`)
			if err := json.Unmarshal([]byte(tocJSON), &toc); err != nil {
				log.Printf("再次解析目录JSON失败: %v", err)
				return
			}
		} else {
			return
		}
	}

	if len(toc) == 0 {
		fmt.Println("目录数据为空")
		return
	}

	fmt.Printf("\n=== 书籍目录结构 (共 %d 章) ===\n", len(toc))

	for _, item := range toc {
		title, titleOK := item["title"].(string)
		if !titleOK || title == "" {
			title = "未知标题"
		}

		level, _ := item["level"].(string)
		selected, _ := item["selected"].(bool)
		disabled, _ := item["disabled"].(bool)

		status := ""
		if selected {
			status += " [当前章节]"
		}
		if disabled {
			status += " [已锁定]"
		}

		var indent string
		switch level {
		case "1":
			indent = "■ "
		case "2":
			indent = "  ├─ "
		case "3":
			indent = "    ├─ "
		default:
			indent = "      ├─ "
		}

		fmt.Printf("%s%s%s\n", indent, title, status)
	}
}

// 清理文件名中的非法字符
func sanitizeFilename(name string) string {
	return strings.Map(func(r rune) rune {
		if r < 32 || r == '\\' || r == '/' || r == ':' || r == '*' ||
			r == '?' || r == '"' || r == '<' || r == '>' || r == '|' {
			return -1
		}
		return r
	}, name)
}
